#!/bin/bash

# 测试用例所在的目录
TEST_CASE_DIR="testcase/src"

# 生成文件所在目录
TEST_OUTPUT_DIR="obj/testcase"

# 设置超时时间
expect_timeout=6

# 创建一个expect脚本模板
# 返回值: 10:正常返回; 50~99:内部终止; 130:Ctrl-C终止 100 ~ 255:错误
expect_template='
spawn make clean_run
expect {
    "For help, type \"help\"" {
        send "c\r"
    }
    "Error" {
        exit 100
    }
}

expect {
    "HIT GOOD TRAP" {
        send "q\r"
        expect eof
        exit 10
    }

    timeout {
        exit 50
    }

    "HIT BAD TRAP" {
        exit 101
    }
    "invalid opcode" {
        exit 102
    }
    "Segmentation fault" {
        exit 103
    }
    "outside of the physical memory" {
        exit 104
    }
}
'

# 找到最长的测试用例名称长度
max_length=0
for file in $TEST_CASE_DIR/*.c; do
    length=${#file}
    if ((length > max_length)); then
        max_length=$length
    fi
done

# 备份 common.h 文件
common_h_file="nemu/include/common.h"
backup_file="${common_h_file}.bak"

# 备份原始文件
cp $common_h_file $backup_file

# 注释掉DEBUG和LOG
sed -i '9s/^/\/\//' $common_h_file # #define DEBUG
sed -i '10s/^/\/\//' $common_h_file # #define LOG_FILE

# 编译测试程序并计时
echo -e "\e[34m正在编译NEMU...\e[0m"
start_time=$(date +%s.%N)
make &> /dev/null
if [ $? -ne 0 ]; then
    echo -e "\e[31m编译NEMU失败\e[0m"
    # 还原 common.h 文件
    mv $backup_file $common_h_file
    exit 1
else
    end_time=$(date +%s.%N)
    elapsed_time=$(echo "$end_time - $start_time" | bc)
    echo -e "\e[34m编译完毕! ( $(printf "%.3f" $elapsed_time) 秒 )\e[0m"
    echo -e "\e[34m开始运行测试程序...\e[0m"
fi

# 遍历目录中的所有.c文件
for file in $TEST_CASE_DIR/*.c
do
    # 获取测试用例的文件名（去掉后缀）
    test_case=$(basename "$file" .c)

    # 更新Makefile中的USERPROG变量
    sed -i "56s/.*/USERPROG := obj\/testcase\/$test_case/" Makefile

    # 计算需要填充的空格数
    padding=$(printf "%*s" $((max_length + 3)) "$test_case" | tr ' ' '.' | sed "s/\.$test_case//")

    # 记录起始时间
    start_time=$(date +%s.%N)

    # 执行expect脚本
    echo -en "正在测试 $test_case$padding\c"
    expect -c "$expect_template" > /dev/null 2>&1

    # 检查expect脚本的退出状态
    case $? in

        # 测试通过
        10)
            end_time=$(date +%s.%N)
            elapsed_time=$(echo "$end_time - $start_time" | bc)
            echo -e "\e[32m测试通过! ( $(printf "%.3f" $elapsed_time) s )\e[0m"

            # 删除测试通过后的相关输出文件
            output_pattern="$TEST_OUTPUT_DIR/$test_case*"
            rm -f $output_pattern
            ;;

        # 测试终止
        50)
            end_time=$(date +%s.%N)
            elapsed_time=$(echo "$end_time - $start_time" | bc)
            echo -e "\e[33m测试超时 ( $(printf "%.3f" $elapsed_time) s )\e[0m"
            ;;
        130)
            echo -e "\e[33m测试终止\e[0m"
            mv $backup_file $common_h_file
            exit 1
            ;;

        # 测试失败
        100)
            echo -e "\e[31m编译失败\e[0m"
            ;;
        101)
            end_time=$(date +%s.%N)
            elapsed_time=$(echo "$end_time - $start_time" | bc)
            echo -e "\e[31m测试失败: 断言失败 ( $(printf "%.3f" $elapsed_time) s )\e[0m"
            ;;
        102)
            end_time=$(date +%s.%N)
            elapsed_time=$(echo "$end_time - $start_time" | bc)
            echo -e "\e[31m测试失败: 非法指令 ( $(printf "%.3f" $elapsed_time) s )\e[0m"
            ;;
        103)  
            end_time=$(date +%s.%N)
            elapsed_time=$(echo "$end_time - $start_time" | bc)
            echo -e "\e[31m段错误 ( $(printf "%.3f" $elapsed_time) s )\e[0m"
            ;;
        104)
            end_time=$(date +%s.%N)
            elapsed_time=$(echo "$end_time - $start_time" | bc)
            echo -e "\e[31m访问非法地址 ( $(printf "%.3f" $elapsed_time) s )\e[0m"
            ;;
        *)
            echo -e "\e[31m测试失败: 未知错误, 返回值为$?\e[0m"
            ;;
    esac
done

# 完成所有测试后还原 common.h 文件
mv $backup_file $common_h_file
echo -e "\e[34m所有测试完成, 已还原 common.h 文件\e[0m"